package de.sendorian.app.forumArchive.dundjinni;

import static de.sendorian.app.forumArchive.matcher.ForumArchiveBuilderMatchers.isAnnouncementOrStickyTopic;
import static de.sendorian.app.forumArchive.matcher.ForumArchiveBuilderMatchers.isIgnorableTopic;
import static org.apache.commons.lang.StringEscapeUtils.unescapeHtml;
import static org.hamcrest.Matchers.any;
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.not;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.htmlparser.NodeFilter;
import org.htmlparser.filters.AndFilter;
import org.htmlparser.filters.HasAttributeFilter;
import org.htmlparser.filters.NotFilter;
import org.htmlparser.filters.TagNameFilter;
import org.htmlparser.nodes.TagNode;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.SimpleNodeIterator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import de.sendorian.app.forumArchive.domain.Topic;
import de.sendorian.app.forumArchive.domain.Topic.Type;
import de.sendorian.app.forumArchive.finder.TopicFinder;
import de.sendorian.app.forumArchive.renamer.ForbiddenCharsRenamer;
import de.sendorian.app.forumArchive.renamer.StringRenamer;


@Component
public class DundjinniTopicFinder extends TopicFinder {

    private static final Logger LOG = Logger.getLogger(DundjinniTopicFinder.class);

    private static final String FORUM_PAGE_PARAM = "&PN=";
    private static final int MAX_FORUM_PAGES = 19;

    private StringRenamer renamer;
    private @Value("#{config.datePattern}") Pattern datePattern;
    private @Value("#{config.dateFormat}") SimpleDateFormat dateFormat;


    public DundjinniTopicFinder() {
        super(any(Topic.class), not(anyOf(isAnnouncementOrStickyTopic(), isIgnorableTopic())), false);
        renamer = new ForbiddenCharsRenamer();
    }


    @Override
    protected String getTopicName(TagNode row) {
        NodeFilter tdFilter = new HasAttributeFilter("width", "41%");
        NodeList tdList = row.getChildren().extractAllNodesThatMatch(tdFilter);
        if (tdList.size() > 0) {
            NodeFilter linkFilter = new TagNameFilter("a");
            NodeList links = ((TagNode) tdList.elementAt(0)).getChildren().extractAllNodesThatMatch(linkFilter);
            if (links.size() > 0) {
                String text = ((TagNode) links.elementAt(0)).getFirstChild().getText();
                return stripForbiddenChars(unescapeHtml(text));
            }
        }
        return null;
    }


    private String stripForbiddenChars(String name) {
        return renamer.rename(name);
    }


    @Override
    protected String getTopicStarter(TagNode row) {
        NodeFilter tdFilter = new HasAttributeFilter("width", "15%");
        NodeList tdList = row.getChildren().extractAllNodesThatMatch(tdFilter);
        if (tdList.size() > 0) {
            NodeFilter linkFilter = new TagNameFilter("a");
            NodeList links = ((TagNode) tdList.elementAt(0)).getChildren().extractAllNodesThatMatch(linkFilter);
            if (links.size() > 0) {
                String text = ((TagNode) links.elementAt(0)).getFirstChild().getText();
                return unescapeHtml(text);
            }
        }
        return null;
    }


    @Override
    protected String getLink(TagNode row) {
        TagNode td = getLastColumn(row);
        if (td == null)
            return null;

        NodeFilter linkFilter = new AndFilter(new TagNameFilter("a"), new NotFilter(new HasAttributeFilter("class",
        "smLink")));
        NodeList linkList = td.getChildren().extractAllNodesThatMatch(linkFilter);
        if (linkList.size() > 0)
            return ((TagNode) linkList.elementAt(0)).getAttribute("href");
        return null;
    }


    @Override
    protected Date getLastPost(TagNode row) {
        TagNode td = getLastColumn(row);
        if (td == null)
            return null;

        SimpleNodeIterator it = td.getChildren().elements();
        while (it.hasMoreNodes()) {
            String nodeText = it.nextNode().toHtml();
            if (!StringUtils.isWhitespace(nodeText)) {
                java.util.regex.Matcher matcher = datePattern.matcher(nodeText);
                if (matcher.find()) {
                    String date = matcher.group(1) + ' ' + matcher.group(2);
                    try {
                        return dateFormat.parse(date);
                    } catch (ParseException e) {
                        LOG.error("Could not parse the date '" + date + "'");
                    }
                }
            }
        }
        return null;
    }


    @Override
    protected Type getType(TagNode row) {
        NodeFilter imageFilter = new AndFilter(new TagNameFilter("img"), new HasAttributeFilter("alt"));
        NodeList imageList = row.getChildren().extractAllNodesThatMatch(imageFilter, true);
        if (imageList.size() > 0)
            return Topic.Type.valueOfDetail(((TagNode) imageList.elementAt(0)).getAttribute("alt"));
        return null;
    }


    @Override
    protected String getNextPage(String url, int actualPageNr) {
        // starting forum page has no page number appended.
        if (!url.contains(FORUM_PAGE_PARAM))
            // the first page is also referenced with page numbers 0 or 1
            return url + FORUM_PAGE_PARAM + "2";

        int nextPageNr = actualPageNr + 1;
        if (nextPageNr <= MAX_FORUM_PAGES)
            return url.substring(0, url.lastIndexOf('=') + 1) + nextPageNr;
        return null;
    }


    private TagNode getLastColumn(TagNode row) {
        NodeList lastColumnList = row.getChildren().extractAllNodesThatMatch(new HasAttributeFilter("class", "smText"));
        if (lastColumnList.size() > 0)
            return (TagNode) lastColumnList.elementAt(0);
        return null;
    }

}
